home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / usenet / sources / volume91 / utilitys / ed3_1_1 / part02 / edgr.c < prev    next >
C/C++ Source or Header  |  1991-11-07  |  17KB  |  811 lines

  1. /*
  2.     These are functions of the 3D editor that handle graphics.
  3.  
  4. 10-16-91 finish_move now checks to see if there is room in the undo buf
  5. 09-26-91 add redraw_newface() (to aid proper screen refreshing)
  6. 09-06-91 add void draw_point_sub()
  7.          adapted to use coord instead of short
  8. 09-04-91 fix to del_face()
  9. 08-28-91 fix black-non-deleted-point glitch
  10. 08-24-91 add glue feature
  11. 08-23-91 add distance_tool(), draw_distance_tool(), draw_distance()
  12. 08-15-91 add circle_point
  13. 08-14-91 (replaced handle_button with handle_gadget)
  14. 08-13-91 added ability to run on the workbench screen
  15. 06-25-90 Polygons added to allow dualization of polyhedra.
  16. */
  17.  
  18. #include "sysgr.h"
  19. #include <math.h>    /* for draw_rot() */
  20.  
  21. extern int gadget_spacing, baseline;
  22. Point3D move_from;            /* base xyz for group moves */
  23.  
  24.  
  25. void draw_3d()
  26. {
  27. }
  28.  
  29.  
  30. /* draw/erase the points currently being dragged */
  31.  
  32. void toggle_dragged_points()
  33. {
  34.     index i, p;
  35.     EdPoint temp;
  36.  
  37.     movement.x = gx - move_from.x;
  38.     movement.y = gy - move_from.y;
  39.     movement.z = gz - move_from.z;
  40.  
  41.     m_setmode(dm_comp);    /* then update it on the screen */
  42.     for (i = 0; i < selected; ++i)
  43.     {
  44.         p = select_p[i];
  45.         temp.x = point[p].x + movement.x;
  46.         temp.y = point[p].y + movement.y;
  47.         temp.z = point[p].z + movement.z;
  48.  
  49.         convert_point_sub(&temp);
  50.         draw_point_sub(&temp);        /* draw/erase */
  51.     }
  52.     m_setmode(dm_norm);
  53. }
  54.  
  55.  
  56. void add_segment(p)
  57. uindex p;
  58. {
  59.     index seg, f;
  60.     int draw_flag = 0;
  61.     Face *fp;
  62.  
  63.     if (p >= points) return;        /* must be valid */
  64.     if (p == last_point) return;    /* don't connect a face to itself */
  65.  
  66.     if (flags.shape == M_FACE)
  67.     {
  68.         fp = face + faces;
  69.  
  70.         switch(new_seg)
  71.         {
  72.             case 2:
  73.                 /* see if a face already exists there */
  74.                 f = points_are_a_face(fp->p[0], fp->p[1], p);
  75.  
  76.                 if (f >= 0)
  77.                 {
  78.                     screen_say("Those three points are already connected by a face");
  79.                     break;
  80.                 }
  81.                 /* notice there is no break here */
  82.             case 1:
  83.                 if (p == fp->p[0]) break;    /* no lines! */
  84.                 fp->p[new_seg++] = p;    /* add this point to the face array */
  85.                 draw_flag = 1;
  86.         }
  87.         if (new_seg == 3)
  88.         {
  89.             tri_up_point(fp->p[0]);    /* erase triangle */
  90.             tri_up_point(fp->p[1]);    /* erase triangle */
  91.  
  92.             /* we could just increment faces, but we call add_faces so that */
  93.             /* the action is logged */
  94.             begin_operation();
  95.             add_face(fp->p[0], fp->p[1], p, colors.newface, 0);    /* not silent */
  96.             end_operation();
  97.  
  98.             m_setpen1(colors.face);
  99.             draw_face(faces-1);
  100.             new_seg = 0;
  101.             mode = M_FACE;
  102.             draw_bars();
  103.             return;
  104.         }
  105.     }
  106.     else if (flags.shape == M_POLY)
  107.     {
  108.         /* polygon completed by clicking the first point */
  109.         if (p == first_point)
  110.         {
  111.             if (new_seg < 3) return;    /* no lines! */
  112.             begin_operation();
  113.             add_poly(new_seg, colors.newface, temp_poly, 0);
  114.             end_operation();
  115.             for (seg = 0; seg < new_seg; seg++)
  116.                 tri_up_point(temp_poly[seg]);    /* erase triangle */
  117.             m_setpen1(colors.face);
  118.             draw_poly(polys-1);        /* draw the newly created polygon */
  119.  
  120.             new_seg = 0;
  121.             mode = M_POLY;
  122.             draw_bars();
  123.             return;
  124.         }
  125.         else    /* add this point to the new polygon */
  126.         {
  127.             /* add this point to the new polygon */
  128.             temp_poly[new_seg++] = p;
  129.             draw_flag = 1;
  130.         }
  131.     }
  132.     if (draw_flag)
  133.     {
  134.         m_setpen1(colors.box);
  135.         convert_to_xy(point[last_point].x, point[last_point].y, point[last_point].z);
  136.         m_move(px, py);
  137.         convert_to_xy(point[p].x, point[p].y, point[p].z);
  138.         m_draw(px, py);
  139.         tri_up_point(p);    /* erase triangle */
  140.         last_point = p;
  141.     }
  142. }
  143.  
  144.  
  145. void del_face(f, silent)
  146. index f;
  147. int silent;
  148. {
  149.     index i1;
  150.     index fa[3], po[3], p[3];
  151.  
  152.     for (i1 = 0; i1 < 3; i1++)    /* remember the points */
  153.         p[i1] = face[f].p[i1];
  154.  
  155.     for (i1 = 0; i1 < 3; i1++)    /* remember the surrounding faces */
  156.     {
  157.         fa[i1] = face_next_to_edge(p[i1], p[(i1+1)%3], f);
  158.         po[i1] = poly_next_to_edge(p[i1], p[(i1+1)%3], -1);
  159.     }
  160.     m_setpen1(colors.erase);
  161.     draw_face(f);
  162.     delete_face(f, silent);
  163.     m_setpen1(colors.face);
  164.     for (i1 = 0; i1 < 3; i1++)    /* redraw the surrounding faces */
  165.     {
  166.         if (fa[i1] == faces) fa[i1] = f;
  167.         if (fa[i1] >= 0)
  168.             draw_face(fa[i1]);
  169.         if (po[i1] >= 0)
  170.             draw_poly(po[i1]);
  171.     }
  172.     for (i1 = 0; i1 < 3; i1++) draw_point(p[i1], colors.point);
  173. }
  174.  
  175.  
  176. void del_poly(q, silent)
  177. index q;
  178. int silent;
  179. {
  180.     index verts, i1;
  181.     index fa[MAX_EDGES], po[MAX_EDGES], p[MAX_EDGES];
  182.  
  183.     verts = poly[q].verts;
  184.  
  185.     for (i1 = 0; i1 < verts; i1++)    /* remember the points */
  186.         p[i1] = poly[q].p[i1];
  187.  
  188.     for (i1 = 0; i1 < verts; i1++)    /* remember the surrounding faces */
  189.     {
  190.         fa[i1] = face_next_to_edge(p[i1], p[(i1+1)%verts], -1);
  191.         po[i1] = poly_next_to_edge(p[i1], p[(i1+1)%verts], q);
  192.     }
  193.     m_setpen1(colors.erase);
  194.     draw_poly(q);
  195.     delete_poly(q, silent);        /* low-level delete */
  196.     m_setpen1(colors.face);
  197.     for (i1 = 0; i1 < verts; i1++)    /* redraw the surrounding faces */
  198.     {
  199.         if (po[i1] == polys) po[i1] = q;
  200.         if (fa[i1] >= 0)
  201.             draw_face(fa[i1]);
  202.         if (po[i1] >= 0)
  203.             draw_poly(po[i1]);
  204.     }
  205.     for (i1 = 0; i1 < verts; i1++) draw_point(p[i1], colors.point);
  206. }
  207.  
  208.  
  209. void kill_segment(p)    /* delete the face/poly that touches this point */
  210. uindex p;
  211. {
  212.     index f, q, seg;
  213.  
  214.     if (p >= points) return;    /* must be valid */
  215.  
  216.     if (flags.shape == M_FACE)
  217.     {
  218.         /* only select a valid point: the new point must be a vertex
  219.             of the face being killed */
  220.         switch (new_seg)
  221.         {
  222.             case 1:
  223.                 f = face_next_to_edge(face[faces].p[0], p, -1);
  224.                 if (f >= 0)
  225.                 {
  226.                     face[faces].p[new_seg++] = p;    /* add this point to the face array */
  227.                     tri_down_point(p);                /* draw triangle */
  228.                 }
  229.                 break;
  230.             case 2:
  231.                 f = points_are_a_face(face[faces].p[0], face[faces].p[1], p);
  232.                 if (f < 0) return;            /* must be valid */
  233.                 tri_down_point(face[faces].p[0]);    /* erase triangles */
  234.                 tri_down_point(face[faces].p[1]);
  235.                 begin_operation();
  236.                 del_face(f, 0);
  237.                 end_operation();
  238.                 new_seg = 0;
  239.                 mode = M_DEFA;
  240.                 draw_bars();
  241. #if 0
  242.                 refresh_all();
  243. #endif
  244.                 return;
  245.                 break;
  246.         }
  247.     }
  248.     else
  249.     if (flags.shape == M_POLY)
  250.     {
  251.         /* polygon completed by clicking the first point */
  252.         if (p == first_point)
  253.         {
  254.             if (new_seg < 3) return;    /* need at least 3 points */
  255.             q = points_are_on_a_poly(temp_poly, new_seg);
  256.             if (new_seg == poly[q].verts)
  257.             {
  258.                 /* found it */
  259.                 for (seg = 0; seg < new_seg; seg++)
  260.                     tri_down_point(temp_poly[seg]);    /* erase triangles */
  261.                 del_poly(q, 0);
  262.                 new_seg = 0;
  263.                 mode = M_DEPO;
  264.                 draw_bars();
  265. #if 0
  266.                 refresh_all();
  267. #endif
  268.                 return;
  269.             }
  270.         }
  271.         else    /* add this point to the killed polygon list */
  272.         {
  273.             temp_poly[new_seg++] = p;    /* add this point to the new polygon */
  274.             q = points_are_on_a_poly(temp_poly, new_seg);
  275.             if (q < 0)    /* not a polygon */
  276.             {
  277.                 new_seg--;
  278.                 return;
  279.             }
  280.             else    /* we have a valid point */
  281.             {
  282.                 tri_down_point(p);    /* draw triangle */
  283.             }
  284.         }
  285.     }
  286. }
  287.  
  288.  
  289. void distance_tool(buttons, current_p)
  290. char buttons;
  291. index current_p;
  292. {
  293.     long dist0, dist1;
  294.     int which_end;
  295.     pixel dx, dy;
  296.  
  297.     if (buttons == 1) return;        /* ignore second button */
  298.  
  299.     /* find which end of the dtool we're closer to */
  300.     convert_to_xy(dtool_end[0].x, dtool_end[0].y, dtool_end[0].z);
  301.     dx = mx - px;
  302.     dy = my - py;
  303.     dist0 = isqrt(dx*dx + dy*dy);
  304.  
  305.     convert_to_xy(dtool_end[1].x, dtool_end[1].y, dtool_end[1].z);
  306.     dx = mx - px;
  307.     dy = my - py;
  308.     dist1 = isqrt(dx*dx + dy*dy);
  309.  
  310.     which_end = (dist1 < dist0);
  311. #if 0
  312.     draw_distance_tool();    /* erase old location */
  313. #endif
  314.     /* if there was no point selected, we cannot allow a double-click */
  315.     if ((buttons & MF_DOUBLE) && current_p < 0) buttons = 0;
  316.  
  317.     switch (buttons)
  318.     {
  319.         case 0:            /* first button clicked once */
  320.             draw_distance_tool();    /* erase old location */
  321.             flags.drag_dtool = 1;
  322.             flags.which_end = which_end;
  323.             dtool_end[which_end].attached = 0;
  324.             draw_distance_tool();    /* draw at new location */
  325.             break;
  326.         case 2:            /* first button double-clicked */
  327.             draw_distance_tool();    /* erase old location */
  328.             flags.drag_dtool = 0;
  329.             dtool_end[which_end].attached = 1;
  330.             dtool_end[which_end].p = current_p;
  331.             draw_distance_tool();    /* draw at new location */
  332.             break;
  333.     }
  334. }
  335.  
  336.  
  337. void finish_move()
  338. {
  339.     index i1;
  340.  
  341.     /* Make sure that this event won't overflow the undo buffer */
  342.     if (!enough_room(0, 0, 0, 0, 0, 0, selected, 0))
  343.     {
  344.         /* this operation will overflow the undo buffer! */
  345.         if (!tell_user_overflow())
  346.         {
  347.             flags.moving_points = 0;
  348.             flags.copy_made = 0;
  349.             return;
  350.         }
  351.     }
  352.     begin_operation();
  353.     for (i1 = 0; i1 < selected; ++i1)
  354.     {
  355.         draw_point(select_p[i1], colors.erase);
  356.  
  357.         /* actually apply the movement specified */
  358.         move_point_rel(select_p[i1], movement.x, movement.y, movement.z);
  359.  
  360.         /* and redraw the point in its new location */
  361.         draw_point(select_p[i1], colors.point);
  362.     }
  363.     end_operation();
  364.     if (faces+polys < REFRESH_LEVEL) refresh_all();    /* kinda arbitrary */
  365.     flags.moving_points = 0;
  366.     flags.copy_made = 0;
  367. }
  368.  
  369.  
  370. void start_moving_point(buttons, p)
  371. int buttons;
  372. uindex p;
  373. {
  374.     index i;
  375.  
  376.     if (p >= points) return;    /* must be valid */
  377.  
  378.     if (!selected || buttons & MF_SHIFTED)    /* select one or multiple points */
  379.     {
  380.         if (buttons & MF_DOUBLE)    /* double click */
  381.         {
  382.             select_connected(p);
  383.         }
  384.         else select_point(p);
  385.     }
  386.     else    /* start to move all selected points */
  387.     {
  388.         flags.moving_points = 1;
  389.         m_setmode(dm_comp);    /* and start xoring */
  390.         for (i = 0; i < selected; i++)
  391.             draw_point(select_p[i], -1);
  392.         m_setmode(dm_norm);
  393.         move_from.x = gx;    /* remember where the mouse went down */
  394.         move_from.y = gy;
  395.         move_from.z = gz;
  396.         movement = vector0;    /* start right here */
  397.     }
  398. }
  399.  
  400.  
  401. void draw_points(clear)
  402. char clear;
  403. {
  404.     uindex p;
  405.  
  406.     if (clear)
  407.     {
  408.         m_setpen1(colors.erase);
  409.         m_rectfill(edit_minx, edit_miny, sxmax, symax);
  410.     }
  411.     for (p = 0; p < points; p++)
  412.     {
  413.         draw_point(p, colors.point);
  414.         if (pselected(p)) box_point(p);
  415.     }
  416. }
  417.  
  418.  
  419. void draw_point(p, pcol)
  420. register uindex p;
  421. int pcol;
  422. {
  423.   if (pcol >= 0) m_setpen1(pcol);    /* -1 means use current color */
  424.   if (p > points) return;        /* must be valid, must allow p == points */
  425.  
  426.   draw_point_sub(point + p);
  427. }
  428.  
  429.  
  430. void draw_point_sub(p)
  431. EdPoint *p;
  432. {
  433.   pixel px, py;
  434.  
  435.   if (p->code & PF_CLIP) return;    /* must be on-screen */
  436.  
  437.   px = p->px;
  438.   py = p->py;
  439.   m_move(px,   py-1);
  440.   m_draw(px,   py+1);
  441.   m_move(px-1, py);
  442.   m_draw(px+1, py);
  443. }
  444.  
  445.  
  446. void draw_hair()
  447. {
  448.     m_setmode(dm_comp);
  449.  
  450.     convert_to_xy(gx, gy, gz);
  451.     m_move(edit_minx,  py);
  452.     m_draw(sxmax-1, py);
  453.     m_move(px, edit_miny+1);
  454.     m_draw(px, symax-1);
  455.  
  456.     m_setmode(dm_norm);
  457. }
  458.  
  459.  
  460. void draw_distance_tool()
  461. {
  462.     index i, p;
  463.     coord x[2], y[2], z[2];
  464.     double dx, dy, dz;
  465.  
  466.     m_setmode(dm_comp);
  467.  
  468.     for (i = 0; i < 2; i++)
  469.     {
  470.         if (dtool_end[i].attached)
  471.         {
  472.             p = dtool_end[i].p;
  473.             dtool_end[i].x = x[i] = point[p].x;
  474.             dtool_end[i].y = y[i] = point[p].y;
  475.             dtool_end[i].z = z[i] = point[p].z;
  476.         }
  477.         else
  478.         {
  479.             x[i] = dtool_end[i].x;
  480.             y[i] = dtool_end[i].y;
  481.             z[i] = dtool_end[i].z;
  482.         }
  483.         convert_to_xy(x[i], y[i], z[i]);
  484.         if (!i)
  485.             m_move(px, py);
  486.         else
  487.             m_draw(px, py);
  488.     }
  489.     m_setmode(dm_norm);
  490.  
  491.     dx = x[1] - x[0];
  492.     dy = y[1] - y[0];
  493.     dz = z[1] - z[0];
  494.     distance = sqrt(dx*dx + dy*dy + dz*dz);
  495.     draw_distance();
  496. }
  497.  
  498.  
  499. void redraw_newface()    /* redraw a partially-completed face or poly */
  500. {
  501.     uindex i1;
  502.  
  503.     /* there must be at least one line segment (2 points) already defined */
  504.     if (new_seg < 2) return;
  505.  
  506.     if (flags.shape == M_FACE)
  507.     {
  508.         for (i1 = 0; i1 < new_seg-1; i1++)
  509.             clip_draw(face[faces].p[i1], face[faces].p[i1+1]);
  510.     }
  511.     else
  512.     {
  513.         for (i1 = 0; i1 < new_seg-1; i1++)
  514.             clip_draw(temp_poly[i1], temp_poly[i1+1]);
  515.     }
  516. }
  517.  
  518.  
  519. void draw_faces(clear)        /* kinda obvious */
  520. char clear;
  521. {
  522.     uindex i;
  523.  
  524.     if (clear)
  525.     {
  526.         m_setpen1(colors.erase);
  527.         m_rectfill(edit_minx, edit_miny, sxmax, symax);
  528.     }
  529.     m_setpen1(colors.face);
  530.     for (i = 0; i < faces; i++) draw_face(i);
  531.     for (i = 0; i < polys; i++) draw_poly(i);    /* do the polygons too */
  532. }
  533.  
  534.  
  535. void draw_face_color(f, col)
  536. uindex f;
  537. int col;
  538. {
  539.     m_setpen1(col);
  540.     draw_face(f);
  541. }
  542.  
  543.  
  544. void draw_face(f)        /* kinda obvious */
  545. uindex f;
  546. {
  547.     uindex p0, p1, p2;
  548.  
  549.     p0 = face[f].p[0];
  550.     p1 = face[f].p[1];
  551.     p2 = face[f].p[2];
  552.  
  553.     clip_draw(p0, p1);
  554.     clip_draw(p1, p2);
  555.     clip_draw(p2, p0);
  556. }
  557.  
  558.  
  559. void draw_poly_color(q, col)        /* kinda obvious */
  560. uindex q;
  561. short col;
  562. {
  563.     m_setpen1(col);
  564.     draw_poly(q);
  565. }
  566.  
  567.  
  568. void draw_poly(p)        /* kinda obvious */
  569. uindex p;
  570. {
  571.     register uindex i, n, next;
  572.  
  573.     n = poly[p].verts;
  574.  
  575.     for (i = 0; i < n; i++)
  576.     {
  577.         next = (i+1==n ? 0 : i+1);
  578.         clip_draw(poly[p].p[i], poly[p].p[next]);
  579.     }
  580. }
  581.  
  582.  
  583. /* draw the little angle-measure thingy */
  584.  
  585. void draw_rot()
  586. {
  587.   pixel x = (pixel)(cos(rot_angle)*50.);
  588.   pixel y = (pixel)(sin(rot_angle)*50.);
  589.  
  590.   m_setmode(dm_comp);
  591.   convert_to_xy(axis.x, axis.y, axis.z);
  592.   m_move(px+50, py);
  593.   m_draw(px,   py);
  594.   m_draw(px+x, py-y);
  595.   m_setmode(dm_norm);
  596. }
  597.  
  598.  
  599. /* Draw the bars which show you what mode and color you're using */
  600.  
  601. void draw_bars()
  602. {
  603.   int y;
  604.  
  605.   /* clear bar region */
  606.   m_setpen1(colors.erase);
  607.   m_rectfill(GADX-6, edit_miny, GADX, symax);
  608.  
  609.   /* editing mode bar */
  610.   m_setpen1(colors.point);
  611.   y = edit_miny + mode * gadget_spacing;
  612.   m_rectfill(GADX-6, y, GADX, y + gadget_spacing);
  613.  
  614.   /* display mode bar */
  615.   m_setpen1(colors.face);
  616.   y = edit_miny + (dmode+GID_XY-1) * gadget_spacing;
  617.   m_rectfill(GADX-6, y, GADX, y + gadget_spacing);
  618.  
  619.   /* color bar */
  620.   m_setpen1(colors.point);
  621.   y = edit_miny + (colors.newface+GID_color1-2) * gadget_spacing;
  622.   m_rectfill(GADX-6, y, GADX, y + gadget_spacing);
  623. }
  624.  
  625.  
  626. void show_counts()
  627. {
  628.   m_setpen1(colors.titlea);
  629.   m_setpen2(colors.titleb);
  630.   m_move(GADX+16, edit_miny+baseline);
  631.   sprintf(title, "%3d points %3d faces %3d polys ", points, faces, polys);
  632.   m_text(title, 31);
  633. }
  634.  
  635.  
  636. void draw_coords(erase)
  637. int erase;
  638. {
  639.   if (erase)
  640.   {
  641.     m_setpen1(colors.erase);
  642.     m_setpen2(colors.erase);
  643.   }
  644.   else
  645.   {
  646.     m_setpen1(colors.titlea);
  647.     m_setpen2(colors.titleb);
  648.   }
  649.   m_move(GADX+280, edit_miny+baseline);
  650. #if INTEGER
  651.   sprintf(title, "X%4d  Y%4d  Z%4d    ", gx, gy, gz);
  652.   m_text(title, 23L);
  653. #else
  654.   sprintf(title, "X%- 10.4lf Y%- 10.4lf Z%- 10.4lf", gx, gy, gz);
  655.   m_text(title, 35L);
  656. #endif
  657. }
  658.  
  659.  
  660. void draw_distance()
  661. {
  662.   m_setpen1(colors.titlea);
  663.   m_setpen2(colors.titleb);
  664.   m_move(GADX+524, edit_miny+baseline);
  665.   sprintf(title, "%4.3f   ", distance);
  666.   m_text(title, 8L);
  667. }
  668.  
  669.  
  670. void box_point(p)        /* draw a box around a point */
  671. register uindex p;
  672. {
  673.   pixel px, py;
  674.  
  675.   if (p >= points) return;    /* must be valid */
  676.   if (off_screen(p)) return;    /* must be on-screen */
  677.  
  678.   m_setmode(dm_comp);
  679.  
  680.   px = point[p].px;
  681.   py = point[p].py;
  682.   m_move(px-2, py-2);
  683.   m_draw(px-2, py+2);
  684.   m_draw(px+2, py+2);
  685.   m_draw(px+2, py-2);
  686.   m_draw(px-2, py-2);
  687.  
  688.   m_setmode(dm_norm);
  689. }
  690.  
  691.  
  692. void tri_up_point(p)        /* draw a triangle around a point */
  693. register uindex p;
  694. {
  695.   pixel px, py;
  696.  
  697.   m_setmode(dm_comp);
  698.  
  699.   if (p >= points) return;        /* must be valid */
  700.   if (off_screen(p)) return;    /* must be on-screen */
  701.  
  702.   px = point[p].px;
  703.   py = point[p].py;
  704.   m_move(px  , py-4);
  705.   m_draw(px-6, py+2);
  706.   m_draw(px+6, py+2);
  707.   m_draw(px+1, py-3);
  708.   m_move(px  , py-3);
  709.   m_draw(px-4, py+1);
  710.   m_move(px+1, py-2);
  711.   m_draw(px+4, py+1);
  712.  
  713.   m_setmode(dm_norm);
  714. }
  715.  
  716.  
  717. void tri_down_point(p)        /* draw a triangle around a point */
  718. register uindex p;
  719. {
  720.   pixel px, py;
  721.  
  722.   m_setmode(dm_comp);
  723.  
  724.   if (p >= points) return;        /* must be valid */
  725.   if (off_screen(p)) return;    /* must be on-screen */
  726.  
  727.   px = point[p].px;
  728.   py = point[p].py;
  729.   m_move(px  , py+4);
  730.   m_draw(px-6, py-2);
  731.   m_draw(px+6, py-2);
  732.   m_draw(px+1, py+3);
  733.   m_move(px  , py+3);
  734.   m_draw(px-4, py-1);
  735.   m_move(px+1, py+2);
  736.   m_draw(px+4, py-1);
  737.  
  738.   m_setmode(dm_norm);
  739. }
  740.  
  741.  
  742. /*
  743.     Draw a line between two points, clipping into the editing area
  744.     if necessary.  Everything is done with pixel coordinates.
  745. */
  746.  
  747. void clip_draw(p0, p1)
  748. register uindex p0, p1;
  749. {
  750.     pixel x0, y0, x1, y1;
  751.     register short c0, c1;
  752.     register pixel dx, dy;        /* clipping codes and distances */
  753.  
  754.     x0 = point[p0].px;
  755.     y0 = point[p0].py;
  756.     x1 = point[p1].px;
  757.     y1 = point[p1].py;
  758.  
  759.     /* pre-generated clipping codes */
  760.     c0 = (point[p0].code & PF_CLIP);
  761.     c1 = (point[p1].code & PF_CLIP);
  762.  
  763. #if 0
  764.     if (flags.debug) printf(" (%d,%d) to (%d, %d), c0 %d, c1 %d.\n",
  765.                         x0, y0, x1, y1, c0, c1);
  766. #endif
  767.     while (c0 | c1)
  768.     {
  769.         if (c0&c1) return;    /* entirely off-screen: don't draw it */
  770.         dx = x1 - x0;
  771.         dy = y1 - y0;
  772.  
  773.         if (c0)
  774.         {
  775.             if (c0 & 8) { y0 += dy*(edit_minx-x0)/dx; x0 = edit_minx; } else
  776.             if (c0 & 4) { y0 += dy*(sxmax-x0)/dx; x0 = sxmax; } else
  777.             if (c0 & 2) { x0 += dx*(edit_miny-y0)/dy; y0 = edit_miny; } else
  778.             if (c0 & 1) { x0 += dx*(symax-y0)/dy; y0 = symax; }
  779.  
  780.             c0 = (x0<edit_minx)<<3 | (x0>sxmax)<<2 | (y0<edit_miny)<<1 | (y0>symax);
  781.         }
  782.         else
  783.         {
  784.             if (c1 & 8) { y1 += dy*(edit_minx-x1)/dx; x1 = edit_minx; } else
  785.             if (c1 & 4) { y1 += dy*(sxmax-x1)/dx; x1 = sxmax; } else
  786.             if (c1 & 2) { x1 += dx*(edit_miny-y1)/dy; y1 = edit_miny; } else
  787.             if (c1 & 1) { x1 += dx*(symax-y1)/dy; y1 = symax; }
  788.  
  789.             c1 = (x1<edit_minx)<<3 | (x1>sxmax)<<2 | (y1<edit_miny)<<1 | (y1>symax);
  790.         }
  791.     }
  792.     m_move(x0, y0);
  793.     m_draw(x1, y1);
  794. }
  795.  
  796.  
  797. void screen_say(str)    /* print a string on the screen's title bar */
  798. char *str;
  799. {
  800.   char string[80];
  801.  
  802.   strncpy(title, str, 80);
  803.   sprintf(string, "%-70s", str);
  804.   m_setpen1(colors.titlea);
  805.   m_setpen2(colors.titleb);
  806.   m_move(GADX+1, edit_miny+baseline);
  807.   m_text(string, 70);
  808. }
  809.  
  810.  
  811.